#ifndef _XX_YY_BMOCK_ARG_VAL
#define _XX_YY_BMOCK_ARG_VAL

#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/any.hpp>
#include <string>
#include "bmock_arg_checker.hpp"
#include "bmock_message.hpp"
#include "bmock_mem_func_ptr_holder.hpp"
#include "bmock_raw_mem.hpp"
#include "hex_value.hpp"

namespace bmock {
	typedef std::pair<std::string,std::string> arg_val_str;
	struct arg_val {			
		static const size_t DEFAULT_PRINT_LENGTH = 16;

		std::string get_name() const { return name_; }
		bool        validate(const arg_checker &chk,const arg_val_str &) const;
		bool		validate_no_msg(const arg_checker &chk, const arg_val_str &) const;
		bool        update(const arg_checker &chk,const arg_val_str &) const;
		virtual arg_val_str get_value(const arg_checker &) const;
		virtual void        print(std::ostream &os) const = 0;
		virtual            ~arg_val();
	protected:		
		arg_val(const char *const n);
		virtual bool        validate(const arg_checker &chk,const std::string &v) const;		
		virtual bool		validate_no_msg(const arg_checker &chk, const std::string &v) const;
		virtual bool        update(const arg_checker &chk,const std::string &v) const;
		virtual void        update(const std::string &v,const control_tools_ptr&,int index) const;
		virtual std::string get_in_value(const arg_checker &) const;
		virtual std::string get_in_value() const;
		virtual std::string get_out_value(const arg_checker &) const;
		virtual void        print_value(std::ostream &os) const;
		virtual bool        null_supplied() const = 0;
		bool        ignore(const std::string &v) const;

		std::string name_;	
	};
	typedef boost::shared_ptr<arg_val> arg_val_ptr;

	template<typename T>
	inline typename boost::enable_if<boost::is_void<T>,std::string>::type 
		__get_value(const T * const ptr) {
			if(NULL==ptr) return NULL_STR;
			return boost::lexical_cast<std::string>(ptr);
	}
	template<typename T>
	inline typename boost::enable_if<boost::is_enum<T>,std::string>::type 
		__get_value(const T * const ptr) {
			if(NULL==ptr) return NULL_STR;
			return boost::lexical_cast<std::string>(int(*ptr));
	}

	template<typename T>
	inline typename boost::enable_if<boost::is_abstract<T>,std::string>::type 
		__get_value(const T * const ptr) {
			if(NULL==ptr) return NULL_STR;
			std::stringstream oss;
			std::string mystr;
			oss<<*ptr;
			mystr=oss.str();
			return mystr;
	}

	template<typename T>
	inline typename boost::disable_if_c<boost::is_pointer<T>::value||boost::is_void<T>::value||boost::is_enum<T>::value||boost::is_member_function_pointer<T>::value||boost::is_function<T>::value||boost::is_abstract<T>::value,std::string>::type 
		__get_value(const T * const ptr) {
			if(NULL==ptr) return NULL_STR;
			return boost::lexical_cast<std::string>(*ptr);
	}
	template<typename T>
	inline typename boost::enable_if<boost::is_pointer<T>,std::string>::type 
		__get_value(const T * const ptr) {
			if(NULL==ptr) return NULL_STR;
			return raw_mem(ptr,1).get_value();
	}

	void insert_to_ptr_vector_(const boost::any& a);

	template<typename T>
	inline typename boost::enable_if<boost::is_member_function_pointer<T>,std::string>::type 
		__get_value(T * ptr) {
			mem_func_ptr_holder<T>* A=new mem_func_ptr_holder<T>(*ptr);
			boost::shared_ptr< mem_func_ptr_holder<T> >X(A);
			boost::any a(X);
			insert_to_ptr_vector_(a);
			return BMOCK_HEX_PREFIX+boost::lexical_cast<std::string>(A->vptr_);
	}

	template<typename T>
	inline typename boost::enable_if<boost::is_function<T>,std::string>::type 
		__get_value(T * ptr) {
			mem_func_ptr_holder<T*>* A=new mem_func_ptr_holder<T*>(ptr);
			boost::shared_ptr< mem_func_ptr_holder<T*> >X(A);
			boost::any a(X);
			insert_to_ptr_vector_(a);
			return BMOCK_HEX_PREFIX+boost::lexical_cast<std::string>(A->vptr_);
	}
	inline std::string __get_value(const char * const ptr) {
		return (NULL==ptr)?NULL_STR:std::string(ptr);
	}
	inline std::string __get_value(const char ptr) {
		return std::string(1,ptr);
	}

	inline std::string __get_value(const unsigned char ptr) {
		return std::string(1,ptr);
	}
	inline std::string __get_value(const unsigned char * const ptr) {
		return __get_value(reinterpret_cast<const char *>(ptr));
	}
}
namespace std {
	std::ostream &operator <<(std::ostream &,const bmock::arg_val_str &);
}
#endif
